module mul_unit(
  input clk,
  input rst,
  input flush,

  input [4:0] op,
  input [63:0] src1,
  input [63:0] src2,
  input [63:0] imm,

  output ready,
  output [63:0] res,
  output valid_o
);
  wire op_MULW,op_MUL,op_MULH,op_MULHSU,op_MULHU;
  assign {op_MULW,op_MUL,op_MULH,op_MULHSU,op_MULHU} = op;

  wire src1_sign = op_MULW | op_MUL | op_MULH | op_MULHSU;
  wire src2_sign = op_MULW | op_MUL | op_MULH;
  wire src1_unsign = op_MULHU;
  wire src2_unsign = op_MULHSU | op_MULHU;
  wire res_sign = op_MULW|op_MUL|op_MULH|op_MULHSU;

  wire [63:0] src1_w = {{32{src1[31]}},src1[31:0]};
  wire [63:0] src2_w = {{32{src2[31]}},src2[31:0]};

  wire op_w = op_MULW;
  wire [63:0] op_val_1 = {64{op_w}}&src1_w | {64{!op_w}}&src1;
  wire [63:0] op_val_2 = {64{op_w}}&src2_w | {64{!op_w}}&src2;
  
  wire signed [64:0] mul_op_1 = { src1_sign&op_val_1[63] , op_val_1};
  wire signed [64:0] mul_op_2 = { src2_sign&op_val_2[63] , op_val_2};

  wire signed [129:0] mul_res = $signed(mul_op_1) * $signed(mul_op_2);

  wire [63:0] res_h;
  wire [63:0] res_l;
// assign res_h = {res_sign&mul_res[129] | !res_sign&mul_res[127],mul_res[126:64]};
// assign res_l = {{32{op_w&mul_res[31]}}|{32{!op_w}}&mul_res[63:32],mul_res[31:0]};
  wire sel_lo = op_MULW | op_MUL;
  wire sel_hi = op_MULH|op_MULHSU|op_MULHU;
  wire sel_lo_r,sel_hi_r;
  Reg #(.WIDTH(2), .RESET_VAL(2'b0)) reg_sel (.clk(clk), .rst(rst|flush), .din({sel_hi,sel_lo}), .dout({sel_hi_r,sel_lo_r}), .wen(valid_i));


  assign res = {64{sel_lo_r}}&res_l | {64{sel_hi_r}}&res_h;
  assign valid_o = |op;
  // assign ready = 1'b1;

  wire valid_i = |op;
  wire mul_valid_o;
  basemul inst_basemul
    (
      .clk        (clk),
      .rst        (rst),
      .valid_i    (valid_i),
      .flush      (flush),
      .mulw       (op_w),
      .mul_signed ({src1_sign&op_val_1[63],src2_sign&op_val_2[63]}),
      .src1       (op_val_1),
      .src2       (op_val_2),
      .ready      (ready),
      .valid_o    (mul_valid_o),
      .res_hi     (res_h),
      .res_lo     (res_l)
    );

endmodule
